package com.bizihang.validate.code.core.support;

import com.bizihang.validate.code.core.Client;
import com.bizihang.validate.code.core.ValidateCode;
import com.bizihang.validate.code.core.ValidateCodeProcessor;
import com.bizihang.validate.code.core.ValidateCodeRepository;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;
import java.util.Optional;

/**
 * 抽象的验证码处理器
 */
public abstract class AbstractValidateCodeProcessor implements ValidateCodeProcessor {

    /**
     * 验证码存储器
     */
    private ValidateCodeRepository defaultValidateCodeRepository = new DefaultValidateCodeRepository();

    /**
     * 修改
     *
     * @param validateCodeRepository
     */
    public void setValidateCodeRepository(ValidateCodeRepository validateCodeRepository) {
        this.defaultValidateCodeRepository = validateCodeRepository;
    }

    /**
     * 获取{@code com.bizihang.validate.code.core.ValidateCodeRepository}
     *
     * @return
     */
    private ValidateCodeRepository getValidateCodeRepository() {
        return defaultValidateCodeRepository;
    }

    @Override
    public void create(Client client) {
        /**
         * 生成验证码
         */
        ValidateCode code = generate(client);
        /**
         * 存储验证码
         */
        storage(client, code);
        /**
         * 发送验证码
         */
        send(client, code);
    }


    @Override
    public void validate(Client client, ValidateCode codeInClient) {
        /**
         * 校验
         */
        this.check(client, codeInClient);
        /**
         * 移除
         */
        getValidateCodeRepository().remove(client);
    }

    @Override
    public void check(Client client, ValidateCode codeInClient) {
        if (Objects.isNull(codeInClient)) {
            throw new RuntimeException("获取验证码的值失败");
        }
        if (StringUtils.isBlank(codeInClient.getCode())) {
            throw new RuntimeException("验证码的值不能为空");
        }

        /**
         * 验证
         */
        Optional<ValidateCode> codeInRepository = getValidateCodeRepository().get(client);

        if (!codeInRepository.isPresent() || codeInRepository.get().isExpired()) {
            getValidateCodeRepository().remove(client);
            throw new RuntimeException("验证码已过期");
        }

        if (!StringUtils.equals(codeInRepository.get().getCode(), codeInClient.getCode())) {
            throw new RuntimeException("验证码不匹配");
        }
    }
    
    /**
     * 生成验证码
     *
     * @param client
     * @return
     */
    protected abstract ValidateCode generate(Client client);

    /**
     * 存储
     *
     * @param code
     * @return
     */
    protected void storage(Client client, ValidateCode code) {
        getValidateCodeRepository().save(client, code);
    }

    /**
     * 发送验证码
     *
     * @param code
     */
    protected abstract void send(Client client, ValidateCode code);
}
